﻿using System;
using GemTowerDefence.Towers;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;

namespace GemTowerDefence.GUI
{
  /// <summary>
  /// Describes the state of the button.
  /// </summary>
  public enum ButtonStatus
  {
    Normal,
    MouseOver,
    Pressed,
  }

  /// <summary>
  /// Stores the appearance and functionality of a button.
  /// </summary>
  public class Button : Sprite
  {
    // Store the MouseState of the last frame.

    // The the different state textures.
    private readonly TowerType _towerType;
    private readonly Texture2D _hoverTexture;
    private readonly Texture2D _pressedTexture;

    // A rectangle that covers the button.
    private Rectangle _bounds;
    private MouseState _previousState;

    // Store the current state of the button.
    private ButtonStatus _state = ButtonStatus.Normal;

    /// <summary>
    /// Constructs a new button.
    /// </summary>
    /// <param name="towerType">The tower type.</param>
    /// <param name="texture">The normal texture for the button.</param>
    /// <param name="hoverTexture">The texture drawn when the mouse is over the button.</param>
    /// <param name="pressedTexture">The texture drawn when the button has been pressed.</param>
    /// <param name="position">The position where the button will be drawn.</param>
    public Button(TowerType towerType, Texture2D texture, Texture2D hoverTexture, Texture2D pressedTexture,
                  Vector2 position)
      : base(texture, position)
    {
      _towerType = towerType;
      _hoverTexture = hoverTexture;
      _pressedTexture = pressedTexture;

      _bounds = new Rectangle((int) position.X, (int) position.Y, texture.Width, texture.Height);
    }

    // Gets fired when the button is pressed.
    public event EventHandler<TowerButtonClickEventArgs> Clicked;
    // Gets fired when the button is held down.
    public event EventHandler<TowerButtonClickEventArgs> OnPress;

    /// <summary>
    /// Updates the buttons state.
    /// </summary>
    /// <param name="gameTime">The current game time.</param>
    public override void Update(GameTime gameTime)
    {
      // Determine if the mouse if over the button.
      MouseState mouseState = Mouse.GetState();

      int mouseX = mouseState.X;
      int mouseY = mouseState.Y;

      bool isMouseOver = _bounds.Contains(mouseX, mouseY);

      // Update the button state.
      if (isMouseOver && _state != ButtonStatus.Pressed)
      {
        _state = ButtonStatus.MouseOver;
      }
      else if (isMouseOver == false && _state != ButtonStatus.Pressed)
      {
        _state = ButtonStatus.Normal;
      }

      // Check if the player holds down the button.
      if (mouseState.LeftButton == ButtonState.Pressed &&
          _previousState.LeftButton == ButtonState.Released)
      {
        if (isMouseOver)
        {
          // Update the button state.
          _state = ButtonStatus.Pressed;

          if (OnPress != null)
          {
            // Fire the OnPress event.
            OnPress(this, new TowerButtonClickEventArgs {Type = _towerType});
          }
        }
      }

      // Check if the player releases the button.
      if (mouseState.LeftButton == ButtonState.Released &&
          _previousState.LeftButton == ButtonState.Pressed)
      {
        if (isMouseOver)
        {
          // update the button state.
          _state = ButtonStatus.MouseOver;

          if (Clicked != null)
          {
            // Fire the clicked event.
            Clicked(this, new TowerButtonClickEventArgs {Type = _towerType});
          }
        }

        else if (_state == ButtonStatus.Pressed)
        {
          _state = ButtonStatus.Normal;
        }
      }

      _previousState = mouseState;
    }

    /// <summary>
    /// Draws the button.
    /// </summary>
    /// <param name="spriteBatch">A SpriteBatch that has been started</param>
    public override void Draw(SpriteBatch spriteBatch)
    {
      switch (_state)
      {
        case ButtonStatus.Normal:
          spriteBatch.Draw(Texture, _bounds, Color.White);
          break;
        case ButtonStatus.MouseOver:
          spriteBatch.Draw(_hoverTexture, _bounds, Color.White);
          break;
        case ButtonStatus.Pressed:
          spriteBatch.Draw(_pressedTexture, _bounds, Color.White);
          break;
        default:
          spriteBatch.Draw(Texture, _bounds, Color.White);
          break;
      }
    }
  }
}